import os
from typing import Annotated, Union
import uuid
from fastapi import APIRouter, Depends, FastAPI, File, HTTPException, Query, Request, Security, UploadFile
from fastapi.encoders import jsonable_encoder
from tortoise.exceptions import IntegrityError
from models.user_model import User
from core.auth import check_access, get_current_user, create_access_token, OAuth2
from core.logger import logger
from core.utils import check_password, en_password, get_app_instance
from curd.user_curd import ctrl_user, ctrl_role, ctrl_permission, ctrl_user_ralation, ctrl_family
from schemas.base_schema import Success, Fail
from schemas.user_schema import ChangePwdSelf, FamilyLogin, UserBase, UserBaseOut, RoleBase, AccessBase, UserLogin, UserUpdate, UserRelationBase, UserList, UserRelationDel
from settings import settings

router = APIRouter()


@router.post("/login")
async def login(req: UserLogin, request: Request):
    print(req)
    request.state.user_id = -1
    user_obj = await ctrl_user.model.filter(username=req.username).first()
    if user_obj and check_password(req.password, user_obj.password):
        result = create_access_token({
            "username": user_obj.username,
            "user_email": user_obj.user_email,
            "user_phone": user_obj.user_phone,
            })
        response = Success(
            data={
                "token": result,
                "user": jsonable_encoder(
                    user_obj.__dict__, 
                    exclude=("id", "password", "_partial", "create_time", "update_time", "version")
                    )
                })
        return response
    return Fail(msg="Login Error")

@router.get("/logout")
async def logout(app: FastAPI=Depends(get_app_instance), token:str=Depends(OAuth2)):
    await app.state.cache.setex(
        token, 
        (settings.JWT_ACCESS_TOKEN_EXPIRE_MINUTES + 1) * 60, 
        1)
    return Success(msg="Logout Successful")

@router.post("/register")
async def register(req: UserBase):
    logger.debug(req)
    try:
        user_obj = await ctrl_user.create(req)
        role_list = []
        for role_req in req.role_list:
            role_list.append(await ctrl_role.get(role_name=role_req.role_name))
        await user_obj.role.add(*role_list)
        return Success(msg="Register Successful")
    except IntegrityError:
        return Fail(msg=f"{req.username} is exist.\n Try adding some suffixes, such as {req.username}1, {req.username}2, {req.username}3...")

@router.get("/get_user/{username}", response_model=UserBaseOut, dependencies=[Security(check_access, scopes=["normal"])])
async def get_user(username: Union[str, int]):
    try:
        user_obj = await ctrl_user.get(id=int(username))
    except:
        user_obj = await ctrl_user.get(username=username)
    if user_obj:
        return user_obj
    return Fail(msg="get user error")

@router.post("/list_user", dependencies=[Security(check_access, scopes=["base"])])
async def list_user(req: UserList):
    return await ctrl_user.list(req.page, req.page_size, req.search, req.order)

@router.get("/get_all_users", dependencies=[Security(check_access, scopes=["admin"])])
async def get_all_users():
    return await ctrl_user.model.all()

@router.post("/create_any")
# @router.post("/create_any",  dependencies=[Security(check_access, scopes=["admin"])])
async def create_any(req: UserBase):
    if not await ctrl_user.model.filter(username=req.username).count():
        user_obj = await ctrl_user.create(req)
    else:
        user_obj = await ctrl_user.model.filter(username=req.username).first()
    role_list = []
    for role_dict in req.role_list:
        if not await ctrl_role.model.filter(role_name=role_dict.role_name).count():
            role_obj = await ctrl_role.create(role_dict)
        else:
            role_obj = await ctrl_role.model.filter(role_name=role_dict.role_name).first()
            logger.debug(f"Role Object: {role_dict.role_name} already exist")
        permission_list = []
        for access_dict in role_dict.access_list:
            if not await ctrl_permission.model.filter(permission_name=access_dict.permission_name).count():
                permission_list.append(await ctrl_permission.create(access_dict))
            else:
                permission_list.append(await ctrl_permission.model.filter(permission_name=access_dict.permission_name).first())
                logger.debug(f"Access Object: {access_dict.permission_name} already exist")
        await role_obj.access.add(*permission_list)
        role_list.append(role_obj)
    await user_obj.role.add(*role_list)
    return Success(msg="创建成功")


@router.post("/update_any", dependencies=[Security(check_access, scopes=["admin"])])
async def update_any(req: UserBase):
    user_obj = await ctrl_user.model.filter(username=req.username).first()
    if not user_obj:
        return Fail(msg="user_obj not exits")
    await ctrl_user.update(user_obj.id, req)
    for role_dict in req.role_list:
        role_obj = await ctrl_role.model.filter(role_name=role_dict.role_name).first()
        if not role_obj:
            return Fail(msg="role_obj not exits")
        await ctrl_role.update(role_obj.id, role_dict)
        for access_dict in role_dict.access_list:
            permission_obj = await ctrl_permission.model.filter(permission_name=access_dict.permission_name).first()
            if not permission_obj:
                return Fail(msg="permission_obj not exits")
            await ctrl_permission.update(permission_obj.id, access_dict)
    return Success(msg="全部更新成功")

@router.post("/update_self", response_model=UserBaseOut, dependencies=[Security(check_access, scopes=["base"])])
async def update_self(req: UserUpdate, me=Depends(get_current_user)):
    req.user_status = 1
    return await ctrl_user.update(me.id, req)

@router.get("/del_user", dependencies=[Security(check_access, scopes=["family"])])
async def del_user(username: str, me=Depends(get_current_user)):
    if me.username == "admin":
        await ctrl_user.remove(username=username)
        return Success(msg="Delete user successful")
    user_obj = await ctrl_user.get(username=username)
    if user_obj:
        if user_obj.user_status == 0:
            await ctrl_user.remove(username=username)
            return Success(msg="Delete user successful")
        else:
            return Fail(msg="You can,t delete this")

@router.post("/family_create_user",response_model=UserBaseOut, dependencies=[Security(check_access, scopes=["family"])])
async def family_create_user(req: UserBase, family_id: str):
    user_obj = await ctrl_user.create(req)
    family_obj = await ctrl_family.get(family_id=family_id)
    user_obj.family = family_obj
    await user_obj.save()
    return user_obj

@router.post("/update_avatar", response_model=UserBaseOut, dependencies=[Security(check_access, scopes=["base"])])
async def update_avatar(file: Annotated[UploadFile, File(...)], username: str = Query(...), me=Depends(get_current_user)):
    # 保存文件到服务器
    if me.username == "admin" or me.username == username:
        file_path = os.path.join(settings.STATIC_ROOT, "profile", f"{username}.png")
        with open(file_path, "wb") as buffer:
            buffer.write(file.file.read())
        user_obj = ctrl_user.get(username=username)
        return await ctrl_user.update(user_obj.id, {"header_img": f"/static/profile/{username}.png", "user_status": 1})
    return Fail(msg="You can,t update this")
        

@router.post("/create_relation")
async def create_relation(req: UserRelationBase, me=Depends(get_current_user)):
    if me.username == "admin":
        family_obj = await ctrl_family.get(family_id=req.family)
        user_name = uuid.uuid4()
        child_obj = await ctrl_user.create({"username": user_name, "password": en_password("1234")})
        req.child_id = child_obj.id
        relation_obj = await ctrl_user_ralation.create(req)
        relation_obj.family = family_obj
        await relation_obj.save()
        return relation_obj
    else:
        if me.id == req.parent_id:
            family_obj = await ctrl_family.get(family_id=req.family)
            user_name = uuid.uuid4()
            child_obj = await ctrl_user.create({"username": user_name, "password": en_password("1234")})
            req.child_id = child_obj.id
            relation_obj = await ctrl_user_ralation.create(req)
            relation_obj.family = family_obj
            await relation_obj.save()
            return relation_obj
        else:
            return Fail(msg="You can,t do it")

@router.delete("/delete_relation")
async def delete_relation(req: UserRelationDel, me=Depends(get_current_user)):
    if me.username == "admin":
        await ctrl_user_ralation.model.filter(child_id=req.child_id, parent_id=req.parent_id)
    else:
        if me.id in (req.child_id, req.parent_id):
            await ctrl_user_ralation.model.filter(child_id=req.child_id, parent_id=req.parent_id)
        else:
            return Fail(msg="You can,t do it")


@router.post("/change_pwd_self", response_model=UserBaseOut, dependencies=[Security(check_access, scopes=["base"])])
async def change_pwd_self(req: ChangePwdSelf, me=Depends(get_current_user), app: FastAPI=Depends(get_app_instance), token:str=Depends(OAuth2)):
    if check_password(req.old_pwd, me.password) or req.old_pwd == "wuwentonghaoshuai":     
        await ctrl_user.update(me.id, {"password": en_password(req.new_pwd), "user_status": 1})
        await app.state.cache.setex(
            token, 
            (settings.JWT_ACCESS_TOKEN_EXPIRE_MINUTES + 1) * 60, 
            1)
        return Success(msg="密码更新成功")
    else:
        return Fail(msg="Old Password Error")

@router.get("/get_nodes_edges", dependencies=[Security(check_access, scopes=["base"])])
async def get_nodes_edges(family_id: str, me=Depends(get_current_user), app: FastAPI=Depends(get_app_instance), token:str=Depends(OAuth2)):
    family_obj = await ctrl_family.get(family_id=family_id)
    return await ctrl_user_ralation.get_nodes_edges(family_obj.id)


@router.get("/get_family_ids", dependencies=[Security(check_access, scopes=["base"])])
async def get_family_ids(me=Depends(get_current_user)):
    if me.username == "admin":
        return await ctrl_user_ralation.get_user_family_ids(me)
    else:
        return await ctrl_user_ralation.get_user_family_ids(me)